package hu.cskassai.sad.gui.mouse;

import hu.cskassai.sad.business.GraphManager;
import hu.cskassai.sad.model.graph.Edge;
import hu.cskassai.sad.model.graph.Vertex2D;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;

import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin;
import edu.uci.ics.jung.visualization.picking.PickedState;

/**
 * a plugin that uses popup menus to create vertices, undirected edges, and directed edges.
 * 
 * @author Tom Nelson
 * 
 */
public class MyEditingPopupGraphMouseMenuPlugin extends AbstractPopupGraphMousePlugin {
	
	protected JPopupMenu popup = new JPopupMenu();
	
	protected GraphManager<Vertex2D, Edge> graphManager;
	
	public MyEditingPopupGraphMouseMenuPlugin(final GraphManager<Vertex2D, Edge> graphManager)
	{
		this.graphManager = graphManager;
	}
	
	@Override
	@SuppressWarnings({ "unchecked", "serial" })
	protected void handlePopup(final MouseEvent e) {
		final VisualizationViewer<Vertex2D, Edge> vv =
			(VisualizationViewer<Vertex2D, Edge>) e.getSource();
		final Layout<Vertex2D, Edge> layout = vv.getGraphLayout();
		final Graph<Vertex2D, Edge> graph = layout.getGraph();
		final Point2D p = e.getPoint();
		final Point2D ivp = p;
		final GraphElementAccessor<Vertex2D, Edge> pickSupport = vv.getPickSupport();
		popup = new JPopupMenu();
		if (pickSupport != null) {
			
			final Vertex2D vertex = pickSupport.getVertex(layout, ivp.getX(), ivp.getY());
			final Edge edge = pickSupport.getEdge(layout, ivp.getX(), ivp.getY());
			final PickedState<Vertex2D> pickedVertexState = vv.getPickedVertexState();
			final PickedState<Edge> pickedEdgeState = vv.getPickedEdgeState();
			
			if (vertex != null) {
				final Set<Vertex2D> picked = pickedVertexState.getPicked();
				if (picked.size() > 0) {
					
					if (graph instanceof DirectedGraph == false) {
						final JMenu undirectedMenu = new JMenu("Create Undirected Edge");
						popup.add(undirectedMenu);
						for (final Vertex2D other : picked) {
							undirectedMenu.add(new AbstractAction("[" + other + "," + vertex + "]") {
								public void actionPerformed(final ActionEvent e) {
									graphManager.addEdge(vertex, other, null);
									vv.repaint();
								}
							});
						}
					}
				}
				popup.add(new AbstractAction("Delete Vertex") {
					public void actionPerformed(final ActionEvent e) {
						pickedVertexState.pick(vertex, false);
						graphManager.deleteVertex(vertex);
						vv.repaint();
					}
				});
				popup.add(new AbstractAction("Set start") {
					public void actionPerformed(final ActionEvent e) {
						graphManager.setToStart(vertex);
						vv.repaint();
					}
				});
				popup.add(new AbstractAction("Set target") {
					public void actionPerformed(final ActionEvent e) {
						graphManager.setToTarget(vertex);
						vv.repaint();
					}
				});
			} else if (edge != null) {
				popup.add(new AbstractAction("Delete Edge") {
					public void actionPerformed(final ActionEvent e) {
						pickedEdgeState.pick(edge, false);
						graphManager.deleteEdge(edge);
						vv.repaint();
					}
				});
			} else {
				popup.add(new AbstractAction("Create Vertex") {
					public void actionPerformed(final ActionEvent e) {
						final Point2D location = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(p);
						graphManager.addVertex(location);
						vv.repaint();
					}
				});
			}
			if (popup.getComponentCount() > 0) {
				popup.show(vv, e.getX(), e.getY());
			}
		}
	}
}
